from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from config import Config
from selenium.webdriver.common.keys import Keys
import time
import datetime
import select
from selenium.webdriver import ChromeOptions


# 用抛出异常来判断一个元素存不存在太慢了，需要等5秒钟
# def isElementExist(ele):
#     flag = True
#     result = EC.presence_of_element_located((By.XPATH, '//tbody[@id="queryLeftTable"]/tr[1]/td[13]/a'))
#     try:
#         # ele.find_element(by=By.CLASS_NAME, value='btn72')
#         result(ele)
#         return flag
#     except:
#         flag = False
#         return flag


# 原作者写的，没看懂啥意思
# def isElementExist(driver):
#     flag=True
#     ele = driver.find_elements(by=By.CLASS_NAME, value='btn72')
#     if len(ele) == 0:
#         flag = False
#         return flag
#     if len(ele) == 1:
#         return flag
#     else:
#         flag = False
#         return flag

def isElementExist(driver):
    # return False

    flag = True
    ele = driver.find_elements(by=By.CLASS_NAME, value='btn72')
    if len(ele) == 0:
        flag = False
        return flag
    if len(ele) > 0:
        return flag
    else:
        flag = False
        return flag


def login(conf, driver, url):
    # driver.maximize_window()
    # 打开网页并发送请求
    driver.get(url)

    Cookie = "uKey=0b3beff14520bdb808cc793cabdb143cd97233834193b96b016df56c56848dab; tk=FDl1SXm_bgIJOGN9ZaCPrDo99Yn3U2e98tMAcFgjQGAozw1w0"
    Cookie = Cookie.split('; ')
    for attribute in Cookie:
        tmp = attribute.split('=')
        driver.add_cookie({'name': tmp[0], 'value': tmp[1]})
        print({'name': tmp[0], 'value': tmp[1]})

    uamtk_cookie = {
        'name': 'uamtk',
        'value': '8Uu5c7lMQ2G0Yiz6YtpA5yoalFHmBVc-5x1KBVKZYPoxhw1w0',
        'Domain': 'kyfw.12306.cn'
    }
    print(uamtk_cookie)

    driver.add_cookie(uamtk_cookie)
    # 发送带有cookie的请求
    driver.get(url)

    # 最多等待5秒使页面加载进来，隐式等待
    driver.implicitly_wait(5)

    # 设置cookie
    # driver.add_cookie({"JSESSIONID": "F881CFC3A09FA419A5EDA3900EAC6663",
    #                    "tk": "g6T9O4BmPKOR1fLaenydzNM1Qkv-kPsA4tIeqQL_cacrww1w0",
    #                    "BIGipServerpassport": "1005060362.50215.0000",
    #                    "guidesStatus": "off",
    #                    "highContrastMode": "defaltMode",
    #                    "cursorStatus": "off",
    #                    "route": "6f50b51faa11b987e576cdb301e545c4",
    #                    "BIGipServerotn": "1473839370.50210.0000",
    #                    "_jc_save_fromStation": "%u5317%u4EAC%2CBJP",
    #                    "_jc_save_toStation": "%u4E0A%u6D77%2CSHH",
    #                    "_jc_save_toDate": "2024-01-22",
    #                    "_jc_save_wfdc_flag": "dc",
    #                    "_jc_save_fromDate": "2024-02-04",
    #                    "uKey": "0b3beff14520bdb808cc793cabdb143ce9e8071e15abeff5ba013845b16aba51"
    #                    })

    # 获取并点击右上角登录按钮
    # login = driver.find_element(by=By.ID, value='J-btn-login')
    # login.click()
    # # driver.implicitly_wait(10)
    #
    # # 账号密码登录
    # username_tag = driver.find_element(by=By.ID, value='J-userName')
    # username_tag.send_keys(conf.username)
    # password_tag = driver.find_element(by=By.ID, value='J-password')
    # password_tag.send_keys(conf.password)
    # login_now = driver.find_element(by=By.ID, value='J-login')
    # login_now.click()
    # time.sleep(2)

    # # 过滑动验证码
    # picture_start = driver.find_element(by=By.ID, value='nc_1_n1z')
    # # 移动到相应的位置，并左键鼠标按住往右边拖
    # ActionChains(driver).move_to_element(picture_start).click_and_hold(picture_start).move_by_offset(300,
    #                                                                                                  0).release().perform()

    '''
    # 扫码登录
    scan_QR = driver.find_element(by=By.XPATH, value='//*[@id="toolbar_Div"]/div[2]/div[2]/ul/li[2]/a')
    scan_QR.click()
    driver.implicitly_wait(10)
    '''

    # 点提示框
    # driver.find_element(by=By.XPATH, value='//div[@class="dzp-confirm"]/div[2]/div[3]/a').click()
    # driver.implicitly_wait(5)

    # 点击车票预订跳转到预订车票页面
    # driver.find_element(by=By.XPATH, value='//*[@id="link_for_ticket"]').click()
    # driver.implicitly_wait(10)


def get_ticket(conf, driver, url):
    # 过网站检测，没加这句的话，账号密码登录时滑动验证码过不了，但二维码登录不受影响
    # driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": """Object.defineProperty(navigator, 'webdriver', {
    #              get: () => undefined})"""})

    # 输入出发地和目的地信息
    # 出发地
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').click()
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').clear()
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').send_keys(conf.fromstation)
    # time.sleep(0.5)
    driver.find_element(by=By.XPATH, value='//*[@id="fromStationText"]').send_keys(Keys.ENTER)

    # 目的地
    destination_tag = driver.find_element(by=By.XPATH, value='//*[@id="toStationText"]')
    destination_tag.click()
    destination_tag.clear()
    destination_tag.send_keys(conf.destination)
    # time.sleep(0.5)
    destination_tag.send_keys(Keys.ENTER)

    # 出发日期
    # driver.implicitly_wait(5)
    date_tag = driver.find_element(by=By.XPATH, value='//*[@id="train_date"]')
    date_tag.click()
    date_tag.clear()
    date_tag.send_keys(conf.date)
    # time.sleep(1)
    date_tag.send_keys(Keys.ENTER)

    # 选中  高铁/动车
    # highDan_tag = driver.find_element(by=By.XPATH, value='//*[@id="isHighDan"]')
    # driver.execute_script("arguments[0].classList.add('active')", highDan_tag)
    # highDan_tag.click()

    # todo: 可以加一些筛选逻辑，比如筛选：高铁动车、二等座等等

    # 点击查询
    search = driver.find_element(by=By.XPATH, value='//*[@id="query_ticket"]')
    driver.execute_script("$(arguments[0]).click()", search)

    # query_tag = driver.find_element(by=By.XPATH, value='//*[@id="search_one"]')
    #
    # driver.execute_script("$(arguments[0]).click()", query_tag)
    # 查询后新打开了一个窗口,切换驱动定位到新页面窗口
    # windows = driver.window_handles
    # driver.switch_to.window(windows[-1])

    start = time.time()

    while True:

        # 判断页面中有没有“预订”按钮，如果没有预订按钮就不断查询直到车票开售
        if not isElementExist(driver):
            # 车票处于待开售状态
            print(f"10点30分起售，现在是{datetime.datetime.now().strftime('%Y%m-%d %H:%M:%S.%f')}，还未开始售票")
            # 每隔两分钟刷新一次，否则3分钟内无购票操作12306系统会自动登出
            if time.time() - start >= 120:
                driver.refresh()
                start = time.time()
            # 延时1秒防止过于快速地点击导致查询超时，当然偶尔还是会出现超时现象，不过超时也没关系，一般等待6秒之后就会继续自动查询
            time.sleep(0.5)

            # 重新点击查询
            search = driver.find_element(by=By.XPATH, value='//*[@id="query_ticket"]')
            driver.execute_script("$(arguments[0]).click()", search)
            continue

        # 获取所有车票
        # // *[ @ id = "ticket_88000G317802_08_22"]
        # tickets = driver.find_elements(by=By.XPATH, value='//*[@id="queryLeftTable"]/tr')

        # 仅获取想要抢票的tr，避免遍历
        tickets = driver.find_elements(by=By.XPATH, value=f'//tr[contains(@id, "{conf.trainnumber}")]')
        # 每张车票有两个tr，但是第二个tr没什么用
        tickets = [tickets[i] for i in range(len(tickets) - 1) if i % 2 == 0]
        if len(tickets) == 0:
            return

            # print(tickets)
        now = datetime.datetime.now().strftime('%Y%m-%d %H:%M:%S.%f')
        print(f"现在是{now}，获取到期望购买的趟次，总趟次：{len(tickets)}")

        # todo:这个for循环效率有点低，后期可以考虑优化一下
        # 上边优化成仅找指定趟次，避免了无效的for循环

        for ticket in tickets:
            # 如果车票的车次等于想要的车次并且硬卧的状态不是候补则点击预订
            # if ticket.find_element(by=By.CLASS_NAME,value='cdz').text== conf.fromstation:
            # print(ticket.find_element(by=By.CLASS_NAME,value='number').text)
            # value = '//td[8]'表示硬卧，td[10]表示硬座,td[4]二等座
            ticketCount = ticket.find_element(by=By.XPATH, value='//td[4]').text

            if ticket.find_element(by=By.CLASS_NAME, value='number').text == conf.trainnumber:
                print(f"找到了需要购买的趟次：{conf.trainnumber}，余票量：{ticketCount}")
                if ticketCount != "候补" and ticketCount != "*":
                    print(f"准备购买趟次：{conf.trainnumber}，余票量：{ticketCount}")
                    # 点击预订
                    # print(ticket.find_element(by=By.CLASS_NAME,value='cdz').text)
                    # time.sleep(1)
                    ticket.find_element(by=By.CLASS_NAME, value='btn72').click()
                    time.sleep(1)

                    # 这里之后就不能继续使用ticket.find_element()了，因为页面进行了跳转，会出现stale element reference: element is not attached to the page document的错误
                    # 我们可以使用driver.find_element()
                    # 选择乘车人，如果是学生，则需要确认购买学生票
                    # driver.find_element(by=By.XPATH, value='//*[@id="normalPassenger_0"]').click()
                    # 点击确认购买学生票，如果不是学生，把这行注释了就行
                    # driver.find_element(by=By.XPATH, value='//*[@id="dialog_xsertcj_ok"]').click()
                    # 第二个乘车人
                    # driver.find_element(by=By.XPATH, value='//*[@id="normalPassenger_1"]').click()
                    # 如果第二个乘车人也是学生，则需要点击确认第二个人也购买学生票
                    # driver.find_element(by=By.XPATH, value='//*[@id="dialog_xsertcj_ok"]').click()

                    # 选择乘车人
                    for passenger in conf.passengers:
                        # 使用XPath定位到包含所需label的li标签
                        # li_element = driver.find_element(By.XPATH, f'//li[label[contains(., "{passenger}")]]')
                        li_element = driver.find_element(By.XPATH,
                                                         f'//ul[@id="normal_passenger_id"]//li[label[contains(., "{passenger}")]]')

                        # 在该li标签内查找input标签
                        input_element = li_element.find_element(By.XPATH, './input')

                        # 对input元素执行操作，例如点击、输入文本等
                        input_element.click()  # 或者 input_element.send_keys("你要输入的文本")

                    # 提交订单
                    driver.find_element(by=By.XPATH, value='//*[@id="submitOrder_id"]').click()
                    # 选座  F座
                    # time.sleep(1)
                    # move = driver.find_element(By.ID, value='1F')
                    # ActionChains(driver).move_to_element(move).perform()
                    # time.sleep(1)
                    # 这里直接使用id和xpath定位不到，所以直接加上他的路径,可以不用这么长，但是懒得删
                    driver.find_element(by=By.XPATH,
                                        value='//html/body/div[5]/div/div[5]/div[1]/div/div[2]/div[2]/div[3]/div[2]/div[2]/ul[2]/li[2]/a[@id="1F"]').click()
                    # 确认提交订单，然后这里和上面是一样的
                    driver.find_element(by=By.XPATH,
                                        value='//html/body/div[5]/div/div[5]/div[1]/div/div[2]/div[2]/div[8]/a[2][@id="qr_submit_id"]').click()
                    print(f"{conf.trainnumber}次列车抢票成功，请尽快在10分钟内支付！")
                    return
        # 重新点击查询
        search = driver.find_element(by=By.XPATH, value='//*[@id="query_ticket"]')
        driver.execute_script("$(arguments[0]).click()", search)
        continue


def login2(conf, driver, url):
    driver.maximize_window()
    driver.get(
        'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E5%8C%97%E4%BA%AC%E5%8C%97,VAP&ts=%E4%B8%8A%E6%B5%B7,SHH&date=2024-01-22&flag=N,N,Y')

    # Cookie = "uKey=0b3beff14520bdb808cc793cabdb143c0c78bba10206106483cfe8d1b1e5c279; tk=9Lcq_9bWSZQN0ZdFkapJJli5QG6u5RJ7wA0kY4Dd5_cfsw1w0"
    # Cookie = Cookie.split('; ')
    # for attribute in Cookie:
    #     tmp = attribute.split('=')
    #     driver.add_cookie({'name': tmp[0], 'value': tmp[1]})
    #     print({'name': tmp[0], 'value': tmp[1]})

    cookies = [
        {
            'name': 'uKey',
            'value': conf.cookie_uKey
        },
        {
            'name': 'tk',
            'value': conf.cookie_tk
        },
        {
            'name': 'uamtk',
            'value': conf.cookie_uamtk
        }
    ]
    for cookie in cookies:
        driver.add_cookie(cookie)

    # 发送带有cookie的请求
    driver.refresh()

    # 最多等待5秒使页面加载进来，隐式等待
    driver.implicitly_wait(5)


if __name__ == '__main__':
    # 有关车票的配置信息保存在该类里
    # 请事先在config.py里填好相关信息
    conf = Config()

    url = 'https://www.12306.cn/index/'

    # chromedriver.exe版本为104，可以根据自己浏览器版本重新下载chromedriver.exe替换
    # chromedriver.exe下载地址：http://chromedriver.storage.googleapis.com/index.html
    # s = Service('C:\Program Files\Google\Chrome\Application\chrome-headless-shell-win64-120.0.6099.109-win64\chrome-headless-shell-win64\chrome-headless-shell.exe')
    # driver = webdriver.Chrome(service=s)

    # 创建Chrome浏览器的选项
    chrome_options = ChromeOptions()

    # 启用cookie支持
    chrome_options.add_argument('--enable-cookie-support')

    # 创建Chrome WebDriver实例
    driver = webdriver.Chrome(options=chrome_options)

    # 登录逻辑
    # login(conf, driver, url)

    # 直接到查询页面
    login2(conf, driver, url)

    # 选票买票
    get_ticket(conf, driver, url)

    time.sleep(10)
    driver.quit()
